package com.xl.rpc.server;

import com.xl.rpc.Request;
import com.xl.rpc.Response;
import com.xl.rpc.codec.Decoder;
import com.xl.rpc.codec.Encoder;
import com.xl.rpc.common.utils.ReflectUtils;
import com.xl.rpc.transport.RequestHandler;
import com.xl.rpc.transport.TransportServer;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author 辜圆圆
 * @description: gzy的项目
 * @date 2020/3/91:41 AM
 */
@Slf4j
public class RpcServer {
    private RpcServerConfig config;
    private TransportServer net;
    private Encoder encoder;
    private Decoder decoder;
    private ServiceManager serviceManager;
    private ServiceInvoke serviceInvoke;

    public RpcServer(){
        this(new RpcServerConfig());
    }

    public RpcServer(RpcServerConfig cofig) {
        this.config = cofig;
        //net
        this.net = ReflectUtils.newInstance(config.getTransportClass());
        this.net.init(config.getPort(),this.handler);
        //codec
        this.encoder = ReflectUtils.newInstance(config.getEncoderClass());
        this.decoder = ReflectUtils.newInstance(config.getDecoderClass());

        //service
        this.serviceManager = new ServiceManager();
        this.serviceInvoke = new ServiceInvoke();
    }


    public void start() {
        this.net.start();
    }

    public void stop() {
        this.net.stop();
    }

    public <T> void register(Class<T> interfaceClass, T bean) {
        serviceManager.register(interfaceClass, bean);
    }

    private RequestHandler handler = new RequestHandler() {
        @Override
        public void onRequest(InputStream recive, OutputStream toResp) {
            Response resp = new Response();
            byte[] inBytes = new byte[0];
            try {
                inBytes = IOUtils.readFully(recive, recive.available());
                Request request = decoder.decode(inBytes, Request.class);
                log.info("get request:{}", request);
                ServiceInstance sis = serviceManager.lookup(request);
                Object ret = serviceInvoke.invoke(sis, request);
                resp.setData(ret);

            } catch (Exception e) {
                log.warn(e.getMessage(), e);
                resp.setCode(1);
                resp.setMsg("RpcServer got error:" + e.getClass().getName()
                        + " " + e.getMessage());
            } finally {
                byte[] outBytes = encoder.encode(resp);
                try {
                    toResp.write(outBytes);
                    log.info("response client");
                } catch (IOException e) {
                    log.warn(e.getMessage(),e);
                }
            }
        }
    };



}

